﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using Crawler.Domain;
using Crawler.Domain.DataEntities;
using Crawler.DomainServices.DataServices;
using HtmlAgilityPack;
using log4net;

namespace Crawler.ContentProcessors
{
	internal class YifiPageContentProcessor : PageContentProcessor
	{
		private const string mdescSelector =
			@"/html[1]/body[1]/div[@id='shell']/div[@class='moviebody']/div[@class='minfo']/div[@class='mdesc']";

		private static readonly ILog Logger = LogManager.GetLogger("AppLogger");


		public YifiPageContentProcessor(IMoviesRepository repository) : base(repository)
		{
		}

		public override TorrentSource ForSource
		{
			get { return TorrentSource.YifyTorrent; }
		}


		private string RemoveIllegalFileNameCharacters(string src)
		{
			string regexSearch = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
			var r = new Regex(string.Format("[{0}]", Regex.Escape(regexSearch)));
			return r.Replace(src, "");
		}


		protected override MovieFile Parse(ProcessableSource src)
		{
			var doc = new HtmlDocument();
			doc.LoadHtml(src.Text);
			if (doc.ParseErrors != null && doc.ParseErrors.Any())
			{
				Logger.WarnFormat("Session: {0} - Parse: {1} - Errors: {2}", src.SessionId, src.AbsoluteUri,
					string.Join(Environment.NewLine, doc.ParseErrors));
				return null;
			}

			bool isNewMovie;
			var result = new MovieFile();

			if (!ParseTitlePart(doc, out isNewMovie, ref result)) return null;
			if (!ParseAttributes(doc, isNewMovie, ref result)) return null;

			if (isNewMovie) AddCrawlInfo(src,result.Movie);

			AddCrawlInfo(src,result);

			return result;
		}

		private bool ParseAttributes(HtmlDocument doc, bool isNewMovie, ref MovieFile result)
		{
			var src = doc.DocumentNode.SelectNodes(string.Concat(mdescSelector, @"/div[@class='inattr']/ul/li"));

			if (isNewMovie)
			{
				UpdateGenre(result, src);

				result.Movie.IMDBRating =
					Single.Parse(WebUtility.HtmlDecode(src.Single(x => x.InnerText.StartsWith("IMDB Rating:"))
						.InnerText.Remove(0, "IMDB Rating:".Length)).Trim().Split('/')[0].Trim());

				result.Movie.MPR =
					src.Single(x => x.InnerText.StartsWith("MPR:")).InnerText.Remove(0, "MPR:".Length).Trim();
			}
			result.Resolution =
				src.Single(x => x.InnerText.StartsWith("Resolution:")).InnerText.Remove(0, "Resolution:".Length).Trim();

			result.QualityCategory =
				src.Single(x => x.InnerText.StartsWith("Quality:")).InnerText.Remove(0, "Quality:".Length).Trim();
			result.FrameRate =
				src.Single(x => x.InnerText.StartsWith("Frame Rate:")).InnerText.Remove(0, "Frame Rate:".Length).Trim();
			result.Language =
				src.Single(x => x.InnerText.StartsWith("Language:")).InnerText.Remove(0, "Language:".Length).Trim();
			result.Duration =
				TimeSpan.FromMinutes(
					int.Parse(src.Single(x => x.InnerText.StartsWith("Run Time:")).InnerText.Remove(0, "Run Time:".Length).Trim()));

			var ps =
				src.Single(x => x.InnerText.StartsWith(@"Peers/Seeds:")).InnerText.Remove(0, @"Peers/Seeds:".Length).Trim();
			result.Peers = int.Parse(ps.Split('/')[0]);
			result.Seeds = int.Parse(ps.Split('/')[1]);
			return true;
		}

		private void UpdateGenre(MovieFile result, HtmlNodeCollection src)
		{
			List<string> genres = src.Single(x => x.InnerText.StartsWith("Genre:")).InnerText.Remove(0, 6).Split('|').ToList();

			result.Movie.Genres = string.Join(",", genres);
		}


		private bool ParseTitlePart(HtmlDocument doc, out bool isNewMovie, ref MovieFile movieFile)
		{
			HtmlNode src = doc.DocumentNode.SelectSingleNode(string.Concat(mdescSelector, @"/div[@class='name']"));

			Match m = Regex.Match(src.InnerText, @"\((\d+)\).*?");

			if (!m.Success)
			{
				isNewMovie = false;
				return false;
			}
			int year = int.Parse(m.Groups[1].Value);


			string[] strings = src.InnerText.Split(new[] {string.Format("({0})", year)}, StringSplitOptions.None);
			string title = strings[0].Trim();
			Movie mov = MoviesRepository.GetMovieByTitle(title, year);
			isNewMovie = mov == null;
			if (isNewMovie)
				mov = new Movie();

			movieFile.Movie = mov;
			if (isNewMovie)
			{
				Movie movie = movieFile.Movie;
				movie.Year = year;
				movie.Title = title;
			}

			strings = strings[1].Trim().Split(' ');

			movieFile.QualityCategory = strings.Length == 2 ? strings[0].Trim() : string.Empty;
			movieFile.FileFormat = strings.Length == 2 ? strings[1].Trim() : strings[0].Trim();


			return true;
		}

		private void AddCrawlInfo(ProcessableSource src, CrawlInfo crawlInfo)
		{
			crawlInfo.FromUrl = src.AbsoluteUri;
			crawlInfo.UtcCrawled = DateTime.UtcNow;
			crawlInfo.SessionId = src.SessionId;
		}

		protected override bool MustProcess(string url)
		{
			return url.ToLower().StartsWith("http://www.yify-torrent.org/movie/");
		}
	}
}